using System;
using System.Xml;
using System.Xml.Linq;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel.Design.Serialization;
using System.ComponentModel.Design;
using System.ComponentModel;
using System.CodeDom;
using System.Data;
using System.Windows.Forms;

namespace GuavaData.Domain
{
    public class DomainConversionException : Exception
    {
        public DomainConversionException(string s)
            : base(s)
        {
            return;
        }
        public DomainConversionException(string s, Exception ie)
            : base(s, ie)
        {
            return;
        }
    }

    public enum GNumericDomains { Integer1Byte, Integer2Byte, Integer4Byte, Integer8Byte, FixedPoint, FloatingPointSingle, FloatingPointDouble }

    [Serializable, Editor(typeof(GuavaEditor), typeof(System.Drawing.Design.UITypeEditor))]
    public abstract class Domain : Object
    {
        public abstract bool Validate(object o);
        public abstract object ConvertString(string s);
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public abstract Type NaiveType { get; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public abstract string DBType { get; }
        public abstract Domain Upcast();
        public abstract object UpcastValue(object o);
        public abstract Domain Merge(Domain d);
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public abstract bool IsOrdered { get; }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public abstract bool CanContain { get;}
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public abstract Domain Clone { get; }
        public virtual List<object> ListOutput()
        {
            return null;
        }
        public static Domain FindRoot(Domain d1, Domain d2)
        {
            if (d1.Equals(d2)) return d1;
            Domain dtemp = d1.Merge(d2);
            if (dtemp != null) return dtemp;
            
            // Create two upcast stacks
            List<Domain> ld1 = new List<Domain>();
            List<Domain> ld2 = new List<Domain>();

            dtemp = d1;
            while (dtemp != null)
            {
                ld1.Add(dtemp);
                dtemp = dtemp.Upcast();
            }

            dtemp = d2;
            while (dtemp != null)
            {
                ld2.Add(dtemp);
                dtemp = dtemp.Upcast();
            }

            // Reverse the lists of upcasts, so that the tops of the trees are first
            ld1.Reverse();
            ld2.Reverse();
            int length = Math.Min(ld1.Count, ld2.Count);

            // Test the treetops, and if they cannot merge, bail
            Domain candidate = ld1[0].Merge(ld2[0]);
            if (candidate == null) return null;

            // Work down the upcast lists, and find the first pair that don't merge 
            for (int iIndex = 1; iIndex < length; iIndex++)
            {
                Domain cTemp = ld1[iIndex].Merge(ld2[iIndex]);
                if (cTemp == null) return candidate;
                candidate = cTemp;
            }

            // If we get to here, then the candidate should be returned
            // This is because one of the domains is in the other's upcast list
            return candidate;
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public virtual System.Windows.Forms.DataGridViewCell GridCellTemplate
        {
            get
            {
                return null;
            }
        }
        public abstract XmlElement ToXml(XmlDocument xdoc);
        public abstract XElement ToXElement();

        public static Domain FromDBInfoRow(DataRow dr)
        {
            var type = dr["Data_Type"].ToString();
            if (type == "bit")
                return Boolean.FromDBInfoRow(dr);
            else if (type == "bigint")
                return BigInteger.FromDBInfoRow(dr);
            else if (type == "int")
                return Integer.FromDBInfoRow(dr);
            else if (type == "smallint")
                return SmallInteger.FromDBInfoRow(dr);
            else if (type == "tinyint")
                return TinyInteger.FromDBInfoRow(dr);
            else if (type == "uniqueidentifier")
                return UniqueIdentifier.FromDBInfoRow(dr);
            else if (type == "varchar")
                return String.FromDBInfoRow(dr);
            else if (type == "nvarchar")
                return String.FromDBInfoRow(dr);
            else if (type == "text")
                return String.FromDBInfoRow(dr);
            else if (type == "datetime")
                return DateTime.FromDBInfoRow(dr);
            else if (type == "float")
                return Double.FromDBInfoRow(dr);
            else if (type == "decimal")
                return Decimal.FromDBInfoRow(dr);
            else if (type == "real")
                return Single.FromDBInfoRow(dr);
            return null;
        }

        public static Domain FromXElement(XElement xe)
        {
            if (xe.Name != "Domain")
                return null;

            // What type should the new domain be?
            var type = xe.Attribute("Type").Value;

            if (type == "Boolean")
                return Boolean.FromXElement(xe);
            else if (type == "BigInteger")
                return BigInteger.FromXElement(xe);
            else if (type == "Integer")
                return Integer.FromXElement(xe);
            else if (type == "SmallInteger")
                return SmallInteger.FromXElement(xe);
            else if (type == "TinyInteger")
                return TinyInteger.FromXElement(xe);
            else if (type == "UniqueIdentifier")
                return UniqueIdentifier.FromXElement(xe);
            else if (type == "String")
                return String.FromXElement(xe);
            else if (type == "DateTime")
                return DateTime.FromXElement(xe);
            else if (type == "Decimal")
                return Decimal.FromXElement(xe);
            else if (type == "Single")
                return Single.FromXElement(xe);
            else if (type == "Double")
                return Double.FromXElement(xe);
            else if (type == "Enumerated")
                return Enumerated.FromXElement(xe);
            else if (type == "Lookup")
                return Lookup.FromXElement(xe);
            return null;
        }
    }

    [TypeConverter(typeof(GuavaDomainConverter))]
    [Serializable]
    public class Boolean : Domain
    {
        public override bool Validate(object o)
        {
            if (o is bool) return true;
            return false;
        }
        public override object ConvertString(string s)
        {
            string v = s.ToLower();
            if (v.Equals("true")) return true;
            if (v.Equals("false")) return false;
            return null;
        }
        public override Type NaiveType
        {
            get { return typeof(bool); }
        }
        public override string DBType
        {
            get { return "bit"; }
        }
        public override string ToString()
        {
            return "Boolean";
        }
        public override bool Equals(object obj)
        {
            return (obj is Boolean);
        }
        public override int GetHashCode()
        {
            return typeof(Boolean).GetHashCode();
        }
        public override Domain Merge(Domain d)
        {
            if (d is Boolean) return this;
            else return null;
        }
        public override Domain Upcast()
        {
            return new TinyInteger();
        }
        public override object UpcastValue(object o)
        {
            if (o is bool)
            {
                if ((bool)o == false) return 0;
                else return 1;
            }
            if (o is string)
            {
                string s = (o as string).ToLower();
                if (s.Equals("true")) return 1;
                if (s.Equals("false")) return 0;
            }

            // If here, not a valid boolean object
            throw new Exception("Object " + o.ToString() + " is not a valid boolean object.");
        }
        public override List<object> ListOutput()
        {
            List<object> lo = new List<object>();
            lo.Add(true);
            lo.Add(false);
            return lo;
        }
        public override bool IsOrdered
        {
            get { return false; }
        }
        public override bool CanContain
        {
            get { return false; }
        }
        public override System.Windows.Forms.DataGridViewCell GridCellTemplate
        {
            get
            {
                return new System.Windows.Forms.DataGridViewCheckBoxCell();
            }
        }
        public override XmlElement ToXml(XmlDocument xdoc)
        {
            XmlElement xe = xdoc.CreateElement("Domain");
            xe.SetAttribute("Type", "Boolean");
            return xe;
        }
        public override XElement ToXElement()
        {
            return new XElement("Domain", new XAttribute("Type", "Boolean"));
        }
        new public static Boolean FromXElement(XElement xe)
        {
            return new Boolean();
        }
        new public static Boolean FromDBInfoRow(DataRow dr)
        {
            return new Boolean();
        }
        public override Domain Clone
        {
            get { return new Boolean(); }
        }
    }

    [TypeConverter(typeof(GuavaDomainConverter))]
    [Serializable]
    public class Enumerated : Domain
    {
        List<string> ls;

        public List<string> Items
        {
            get { return ls; }
            set { ls = value; }
        }

        public Enumerated()
        {
            ls = new List<string>();
        }
        public Enumerated(IEnumerable<string> array)
            : this()
        {
            foreach (string s in array)
                ls.Add(s);
        }
        public int Length
        {
            get
            {
                //if (ls.Count <= 0) throw new Exception("Cannot have an empty enumerated type.");
                int i = 0;
                foreach (string s in ls) if (s.Length > i) i = s.Length;
                return i;
            }
        }        
        public override bool Validate(object o)
        {
            if (! (o is string)) return false;
            if (ls.Contains(o as string)) return true;
            return false;
        }
        public override object ConvertString(string s)
        {
            if (ls.Contains(s)) return s;
            throw new DomainConversionException("String value " + s + " is not a value in this Enumerated type.");
        }
        public override Type NaiveType
        {
            get { return typeof(string); }
        }
        public override string DBType
        {
            get { return "varchar(" + this.Length.ToString() + ")"; }
        }
        public override bool Equals(object obj)
        {
            if (! (obj is Enumerated)) return false;
            if ((obj as Enumerated).ls.Count != this.ls.Count) return false;
            for (int i = 0; i < this.ls.Count; i++)
            {
                if ((obj as Enumerated).ls[i] != this.ls[i]) return false;
            }
            return true;
        }
        public override int GetHashCode()
        {
            int temp = typeof(Enumerated).GetHashCode();
            foreach (string s in ls) temp += s.GetHashCode();
            return temp;
        }
        public override string ToString()
        {
            return "Enumerated";
        }
        public override Domain Merge(Domain d)
        {
            if (!(d is Enumerated)) return null;
            Enumerated e = new Enumerated();
            foreach (string s in this.ls) e.ls.Add(s);
            foreach (string s in (d as Enumerated).ls) if (!(e.ls.Contains(s))) e.ls.Add(s);
            
            // We need the merge operation to be commutative, so sort the list
            e.ls.Sort();
            return e;
        }
        public override Domain Upcast()
        {
            return new String(this.Length);
        }
        public override object UpcastValue(object o)
        {
            return o;
        }
        public override List<object> ListOutput()
        {
            return ls.ConvertAll(new Converter<string, object>(delegate(string s) { return (s as object); }));
        }
        public override bool IsOrdered
        {
            get { return false; }
        }
        public override bool CanContain
        {
            get { return false; }
        }
        public override System.Windows.Forms.DataGridViewCell GridCellTemplate
        {
            get
            {
                System.Windows.Forms.DataGridViewComboBoxCell dgvc = new System.Windows.Forms.DataGridViewComboBoxCell();
                dgvc.Items.Clear();
                dgvc.Items.AddRange(ls.ToArray());
                return dgvc;
            }
        }
        public override XmlElement ToXml(XmlDocument xdoc)
        {
            XmlElement xe = xdoc.CreateElement("Domain");
            xe.SetAttribute("Type", "Enumerated");
            foreach (string s in Items)
            {
                XmlElement item = xdoc.CreateElement("Item");
                XmlText xt = xdoc.CreateTextNode(s);
                item.AppendChild(xt);
                xe.AppendChild(item);
            }
            return xe;
        }
        public override XElement ToXElement()
        {
            var xe = new XElement("Domain", new XAttribute("Type", "Enumerated"));
            foreach (var s in Items)
            {
                xe.Add(new XElement("Item", new XText(s)));
            }
            return xe;
        }
        new internal static Enumerated FromXElement(XElement xe)
        {
            var o = new Enumerated();
            var i = from elt in xe.Elements("Item")
                    select elt.Value;
            o.Items = new List<string>(i);
            return o;
        }
        public override Domain Clone
        {
            get { return new Enumerated(new List<string>(this.Items)); }
        }
    }

    [TypeConverter(typeof(GuavaDomainConverter))]
    [Serializable]
    public class BigInteger : Domain
    {
        long? max;
        long? min;
        public long? Max
        {
            get { return max; }
            set { max = value; }
        }
        public long? Min
        {
            get { return min; }
            set { min = value; }
        }
        public BigInteger()
        {
            max = null;
            min = null;
        }
        public BigInteger(long? min, long? max)
        {
            this.min = min;
            this.max = max;
        }
        public override bool Validate(object o)
        {
            long? i = null;

            if (o == null) return true;
            if (o is long?) i = o as long?;

            // If still null at this point, then o isn't a valid byte-worthy object
            if (i == null) return false;
            if ((min != null) && (min > i)) return false;
            if ((max != null) && (max < i)) return false;
            return true;
        }
        public override object ConvertString(string s)
        {
            if ((s == null) || (s == "")) return null;
            long d;
            if (Int64.TryParse(s, out d))
            {
                if ((min != null) && (min > d)) throw new DomainConversionException("Value " + s + " is too small for a domain with minimum value " + min.ToString() + ".");
                if ((max != null) && (max < d)) throw new DomainConversionException("Value " + s + " is too big for a domain with maximum value " + max.ToString() + ".");
                return d;
            }
            else
            {
                throw new DomainConversionException("Could not convert " + s + " into a 64-bit integer.");
            }
        }
        public override Type NaiveType
        {
            get { return typeof(Int64); }
        }
        public override string DBType
        {
            get { return "bigint"; }
        }
        public override bool Equals(object obj)
        {
            if (!(obj is BigInteger)) return false;
            BigInteger that = obj as BigInteger;
            return ((this.max == that.max) && (this.min == that.min));
        }
        public override int GetHashCode()
        {
            return typeof(BigInteger).GetHashCode() * (min.GetHashCode() + 1) + max.GetHashCode();
        }
        public override string ToString()
        {
            return "BigInteger";
        }
        public override Domain Merge(Domain d)
        {
            if (!(d is BigInteger)) return null;
            BigInteger that = d as BigInteger;
            long? nmax = (this.max == that.max) ? this.max : null;
            long? nmin = (this.min == that.min) ? this.min : null;
            return new BigInteger(nmin, nmax);
        }
        public override Domain Upcast()
        {
            return null;
        }
        public override object UpcastValue(object o)
        {
            // This is the root of an upcast tree, so return null
            return null;
        }
        public override bool IsOrdered
        {
            get { return true; }
        }
        public override bool CanContain
        {
            get { return false; }
        }
        public override System.Windows.Forms.DataGridViewCell GridCellTemplate
        {
            get
            {
                DataGridViewNumberBoxCell dv = new DataGridViewNumberBoxCell();
                dv.Dom = GNumericDomains.Integer8Byte;
                return dv;
            }
        }
        public override XmlElement ToXml(XmlDocument xdoc)
        {
            XmlElement xe = xdoc.CreateElement("Domain");
            xe.SetAttribute("Type", "BigInteger");
            if (max != null) xe.SetAttribute("MaxValue", max.ToString());
            if (min != null) xe.SetAttribute("MinValue", min.ToString());
            return xe;
        }
        public override XElement ToXElement()
        {
            var xe = new XElement("Domain", new XAttribute("Type", "BigInteger"));
            if (max != null) xe.SetAttributeValue("MaxValue", max.ToString());
            if (min != null) xe.SetAttributeValue("MinValue", min.ToString());
            return xe;
        }
        new internal static BigInteger FromXElement(XElement xe)
        {
            var o = new BigInteger();
            if (xe.Attribute("MaxValue") != null)
                o.max = Int64.Parse(xe.Attribute("MaxValue").Value);
            if (xe.Attribute("MinValue") != null)
                o.min = Int64.Parse(xe.Attribute("MinValue").Value);
            return o;
        }
        new internal static BigInteger FromDBInfoRow(DataRow dr)
        {
            var o = new BigInteger();
            return o;
        }
        public override Domain Clone
        {
            get { return new BigInteger(this.min, this.max); }
        }
    }

    [TypeConverter(typeof(GuavaDomainConverter))]
    [Serializable]
    public class Integer : Domain
    {
        int? max;
        int? min;
        public int? Max
        {
            get { return max; }
            set { max = value; }
        }
        public int? Min
        {
            get { return min; }
            set { min = value; }
        }
        public Integer()
        {
            max = null;
            min = null;
        }
        public Integer(int? min, int? max)
        {
            this.min = min;
            this.max = max;
        }
        public override bool Validate(object o)
        {
            int? i = null;

            if (o == null) return true;
            if (o is int?) i = o as int?;

            // If still null at this point, then o isn't a valid byte-worthy object
            if (i == null) return false;
            if ((min != null) && (min > i)) return false;
            if ((max != null) && (max < i)) return false;
            return true;
        }
        public override object ConvertString(string s)
        {
            if ((s == null) || (s == "")) return null;
            int d;
            if (Int32.TryParse(s, out d))
            {
                if ((min != null) && (min > d)) throw new DomainConversionException("Value " + s + " is too small for a domain with minimum value " + min.ToString() + ".");
                if ((max != null) && (max < d)) throw new DomainConversionException("Value " + s + " is too big for a domain with maximum value " + max.ToString() + ".");
                return d;
            }
            else
            {
                throw new DomainConversionException("Could not convert " + s + " into a 32-bit integer.");
            }
        }
        public override Type NaiveType
        {
            get { return typeof(Int32); }
        }
        public override string DBType
        {
            get { return "int"; }
        }
        public override bool Equals(object obj)
        {
            if (!(obj is Integer)) return false;
            Integer that = obj as Integer;
            return ((this.max == that.max) && (this.min == that.min));
        }
        public override int GetHashCode()
        {
            return typeof(Integer).GetHashCode() * (min.GetHashCode() + 1) + max.GetHashCode();
        }
        public override string ToString()
        {
            return "Integer";
        }
        public override Domain Merge(Domain d)
        {
            if (!(d is Integer)) return null;
            Integer that = d as Integer;
            int? nmax = (this.max == that.max) ? this.max : null;
            int? nmin = (this.min == that.min) ? this.min : null;
            return new Integer(nmin, nmax);
        }
        public override Domain Upcast()
        {
            return new BigInteger((Int64?)min, (Int64?)max);
        }
        public override object UpcastValue(object o)
        {
            if (o == null) return null;
            if (o is Int32?) return (Int64?)o;
            return null;
        }
        public override bool IsOrdered
        {
            get { return true; }
        }
        public override bool CanContain
        {
            get { return false; }
        }
        public override System.Windows.Forms.DataGridViewCell GridCellTemplate
        {
            get
            {
                DataGridViewNumberBoxCell dv = new DataGridViewNumberBoxCell();
                dv.Dom = GNumericDomains.Integer4Byte;
                return dv;
            }
        }
        public override XmlElement ToXml(XmlDocument xdoc)
        {
            XmlElement xe = xdoc.CreateElement("Domain");
            xe.SetAttribute("Type", "Integer");
            if (max != null) xe.SetAttribute("MaxValue", max.ToString());
            if (min != null) xe.SetAttribute("MinValue", min.ToString());
            return xe;
        }
        public override XElement ToXElement()
        {
            var xe = new XElement("Domain", new XAttribute("Type", "Integer"));
            if (max != null) xe.SetAttributeValue("MaxValue", max.ToString());
            if (min != null) xe.SetAttributeValue("MinValue", min.ToString());
            return xe;
        }
        new internal static Integer FromXElement(XElement xe)
        {
            var o = new Integer();
            if (xe.Attribute("MaxValue") != null)
                o.max = int.Parse(xe.Attribute("MaxValue").Value);
            if (xe.Attribute("MinValue") != null)
                o.min = int.Parse(xe.Attribute("MinValue").Value);
            return o;
        }
        new internal static Integer FromDBInfoRow(DataRow dr)
        {
            var o = new Integer();
            return o;
        }
        public override Domain Clone
        {
            get { return new Integer(this.min, this.max); }
        }
    }

    [TypeConverter(typeof(GuavaDomainConverter))]
    [Serializable]
    public class SmallInteger : Domain
    {
        short? max;
        short? min;
        public short? Max
        {
            get { return max; }
            set { max = value; }
        }
        public short? Min
        {
            get { return min; }
            set { min = value; }
        }
        public SmallInteger()
        {
            max = null;
            min = null;
        }
        public SmallInteger(short? min, short? max)
        {
            this.min = min;
            this.max = max;
        }
        public override bool Validate(object o)
        {
            short? i = null;

            if (o == null) return true;
            if (o is short?) i = o as short?;

            // If still null at this point, then o isn't a valid byte-worthy object
            if (i == null) return false;
            if ((min != null) && (min > i)) return false;
            if ((max != null) && (max < i)) return false;
            return true;
        }
        public override object ConvertString(string s)
        {
            if ((s == null) || (s == "")) return null;
            short d;
            if (Int16.TryParse(s, out d))
            {
                if ((min != null) && (min > d)) throw new DomainConversionException("Value " + s + " is too small for a domain with minimum value " + min.ToString() + ".");
                if ((max != null) && (max < d)) throw new DomainConversionException("Value " + s + " is too big for a domain with maximum value " + max.ToString() + ".");
                return d;
            }
            else
            {
                throw new DomainConversionException("Could not convert " + s + " into a 16-bit integer.");
            }
        }
        public override Type NaiveType
        {
            get { return typeof(Int16); }
        }
        public override string DBType
        {
            get { return "smallint"; }
        }
        public override bool Equals(object obj)
        {
            if (!(obj is SmallInteger)) return false;
            SmallInteger that = obj as SmallInteger;
            return ((this.max == that.max) && (this.min == that.min));
        }
        public override int GetHashCode()
        {
            return typeof(SmallInteger).GetHashCode() * (min.GetHashCode() + 1) + max.GetHashCode();
        }
        public override string ToString()
        {
            return "SmallInteger";
        }
        public override Domain Merge(Domain d)
        {
            if (!(d is SmallInteger)) return null;
            SmallInteger that = d as SmallInteger;
            short? nmax = (this.max == that.max) ? this.max : null;
            short? nmin = (this.min == that.min) ? this.min : null;
            return new SmallInteger(nmin, nmax);
        }
        public override Domain Upcast()
        {
            return new Integer((Int32?)min, (Int32?)max);
        }
        public override object UpcastValue(object o)
        {
            if (o == null) return null;
            if (o is Int16?) return (Int32?)o;
            return null;
        }
        public override bool IsOrdered
        {
            get { return true; }
        }
        public override bool CanContain
        {
            get { return false; }
        }
        public override System.Windows.Forms.DataGridViewCell GridCellTemplate
        {
            get
            {
                DataGridViewNumberBoxCell dv = new DataGridViewNumberBoxCell();
                dv.Dom = GNumericDomains.Integer2Byte;
                return dv;
            }
        }

        public override XmlElement ToXml(XmlDocument xdoc)
        {
            XmlElement xe = xdoc.CreateElement("Domain");
            xe.SetAttribute("Type", "SmallInteger");
            if (max != null) xe.SetAttribute("MaxValue", max.ToString());
            if (min != null) xe.SetAttribute("MinValue", min.ToString());
            return xe;
        }

        public override XElement ToXElement()
        {
            var xe = new XElement("Domain", new XAttribute("Type", "SmallInteger"));
            if (max != null) xe.SetAttributeValue("MaxValue", max.ToString());
            if (min != null) xe.SetAttributeValue("MinValue", min.ToString());
            return xe;
        }
        new internal static SmallInteger FromXElement(XElement xe)
        {
            var o = new SmallInteger();
            if (xe.Attribute("MaxValue") != null)
                o.max = short.Parse(xe.Attribute("MaxValue").Value);
            if (xe.Attribute("MinValue") != null)
                o.min = short.Parse(xe.Attribute("MinValue").Value);
            return o;
        }
        new internal static SmallInteger FromDBInfoRow(DataRow dr)
        {
            var o = new SmallInteger();
            return o;
        }
        public override Domain Clone
        {
            get { return new SmallInteger(this.min, this.max); }
        }
    }

    [TypeConverter(typeof(GuavaDomainConverter))]
    [Serializable]
    public class TinyInteger : Domain
    {
        byte? max;
        byte? min;
        public byte? Max
        {
            get { return max; }
            set { max = value; }
        }
        public byte? Min
        {
            get { return min; }
            set { min = value; }
        }

        public TinyInteger()
        {
            max = null;
            min = null;
        }
        public TinyInteger(byte? min, byte? max)
        {
            this.min = min;
            this.max = max;
        }
        public override bool Validate(object o)
        {
            byte? i = null;
            
            if (o == null) return true;
            if (o is byte?) i = o as byte?;
            
            // If still null at this point, then o isn't a valid byte-worthy object
            if (i == null) return false;
            if ((min != null) && (min > i)) return false;
            if ((max != null) && (max < i)) return false;
            return true;
        }
        public override object ConvertString(string s)
        {
            if ((s == null) || (s == "")) return null;
            byte d;
            if (Byte.TryParse(s, out d))
            {
                if ((min != null) && (min > d)) throw new DomainConversionException("Value " + s + " is too small for a domain with minimum value " + min.ToString() + ".");
                if ((max != null) && (max < d)) throw new DomainConversionException("Value " + s + " is too big for a domain with maximum value " + max.ToString() + ".");
                return d;
            }
            else
            {
                throw new DomainConversionException("Could not convert " + s + " into an 8-bit integer.");
            }
        }
        public override Type NaiveType
        {
            get { return typeof(byte); }
        }
        public override string DBType
        {
            get { return "tinyint"; }
        }
        public override bool Equals(object obj)
        {
            if (!(obj is TinyInteger)) return false;
            TinyInteger that = obj as TinyInteger;
            return ((this.max == that.max) && (this.min == that.min));
        }
        public override int GetHashCode()
        {
            return typeof(TinyInteger).GetHashCode() * (min.GetHashCode() + 1) + max.GetHashCode();
        }
        public override string ToString()
        {
            return "TinyInteger";
        }
        public override Domain Merge(Domain d)
        {
            if (!(d is TinyInteger)) return null;
            TinyInteger that = d as TinyInteger;
            byte? nmax = (this.max == that.max) ? this.max : null;
            byte? nmin = (this.min == that.min) ? this.min : null;
            return new TinyInteger(nmin, nmax);
        }
        public override Domain Upcast()
        {
            return new SmallInteger((Int16?)min, (Int16?)max);
        }
        public override object UpcastValue(object o)
        {
            if (o == null) return null;
            if (o is byte?) return (Int16?)o;
            return null;
        }
        public override bool IsOrdered
        {
            get { return true; }
        }
        public override bool CanContain
        {
            get { return false; }
        }
        public override System.Windows.Forms.DataGridViewCell GridCellTemplate
        {
            get
            {
                DataGridViewNumberBoxCell dv = new DataGridViewNumberBoxCell();
                dv.Dom = GNumericDomains.Integer1Byte;
                return dv;
            }
        }
        public override XmlElement ToXml(XmlDocument xdoc)
        {
            XmlElement xe = xdoc.CreateElement("Domain");
            xe.SetAttribute("Type", "TinyInteger");
            if (max != null) xe.SetAttribute("MaxValue", max.ToString());
            if (min != null) xe.SetAttribute("MinValue", min.ToString());
            return xe;
        }
        public override XElement ToXElement()
        {
            var xe = new XElement("Domain", new XAttribute("Type", "TinyInteger"));
            if (max != null) xe.SetAttributeValue("MaxValue", max.ToString());
            if (min != null) xe.SetAttributeValue("MinValue", min.ToString());
            return xe;
        }
        new internal static TinyInteger FromXElement(XElement xe)
        {
            var o = new TinyInteger();
            if (xe.Attribute("MaxValue") != null)
                o.max = Byte.Parse(xe.Attribute("MaxValue").Value);
            if (xe.Attribute("MinValue") != null)
                o.min = Byte.Parse(xe.Attribute("MinValue").Value);
            return o;
        }
        new internal static TinyInteger FromDBInfoRow(DataRow dr)
        {
            var o = new TinyInteger();
            return o;
        }
        public override Domain Clone
        {
            get { return new TinyInteger(this.min, this.max); }
        }

    }

    [TypeConverter(typeof(GuavaDomainConverter))]
    [Serializable]
    public class UniqueIdentifier : Domain
    {
        public override bool Validate(object o)
        {
            if (o == null) return true;
            if (o is Guid) return true;
            return false;
        }
        public override object ConvertString(string s)
        {
            try
            {
                return new Guid(s);
            }
            catch (FormatException fe)
            {
                throw new DomainConversionException(fe.Message, fe);
            }
            catch (OverflowException oe)
            {
                throw new DomainConversionException(oe.Message, oe);
            }
        }
        public override Type NaiveType
        {
            get { return typeof(Guid); }
        }
        public override string DBType
        {
            get { return "uniqueidentifier"; }
        }
        public override bool Equals(object obj)
        {
            return (obj is UniqueIdentifier);
        }
        public override int GetHashCode()
        {
            return typeof(UniqueIdentifier).GetHashCode();
        }
        public override string ToString()
        {
            return "UniqueIdentifier";
        }
        public override Domain Merge(Domain d)
        {
            if (d is UniqueIdentifier) return this;
            return null;
        }
        public override Domain Upcast()
        {
            return null;
        }
        public override object UpcastValue(object o)
        {
            return null;
        }
        public override bool IsOrdered
        {
            get { return false; }
        }
        public override bool CanContain
        {
            get { return false; }
        }
        public override XmlElement ToXml(XmlDocument xdoc)
        {
            XmlElement xe = xdoc.CreateElement("Domain");
            xe.SetAttribute("Type", "UniqueIdentifier");
            return xe;
        }
        public override XElement ToXElement()
        {
            return new XElement("Domain", new XAttribute("Type", "UniqueIdentifier"));
        }
        new internal static UniqueIdentifier FromXElement(XElement xe)
        {
            return new UniqueIdentifier();
        }
        new internal static UniqueIdentifier FromDBInfoRow(DataRow dr)
        {
            var o = new UniqueIdentifier();
            return o;
        }
        public override Domain Clone
        {
            get { return new UniqueIdentifier(); }
        }
    }

    [TypeConverter(typeof(GuavaDomainConverter))]
    [Serializable]
    public class Lookup : Domain
    {
        string view;
        string tableName;
        public string View
        {
            get { return view; }
            set { view = value; }
        }
        public string TableName
        {
            get { return tableName; }
            set { tableName = value; }
        }

        public Lookup(string table, string view)
        {
            this.tableName = table;
            this.view = view;
        }
        public override bool Validate(object o)
        {
            if (o == null) return true;
            if (o is Guid) return true;
            return false;
        }
        public override object ConvertString(string s)
        {
            return new Guid(s);
        }
        public override Type NaiveType
        {
            get { return typeof(Guid); }
        }
        public override string DBType
        {
            get { return "uniqueidentifier"; }
        }
        public override bool Equals(object obj)
        {
            return ((obj is Lookup) && ((obj as Lookup).view == this.view) && ((obj as Lookup).tableName == this.tableName));
        }
        public override int GetHashCode()
        {
            return typeof(Lookup).GetHashCode() + view.GetHashCode() * tableName.GetHashCode();
        }
        public override string ToString()
        {
            return "InternalLookup: " + this.tableName;
        }
        public override Domain Merge(Domain d)
        {
            if (this.Equals(d)) return this;
            return null;
        }
        public override Domain Upcast()
        {
            return new UniqueIdentifier();
        }
        public override object UpcastValue(object o)
        {
            return o;
        }
        public override bool IsOrdered
        {
            get { return false; }
        }
        public override bool CanContain
        {
            get { return false; }
        }
        public override List<object> ListOutput()
        {
            System.Data.DataTable dt = AppData.FetchAllRows(tableName);

            List<object> lo = new List<object>();
            List<string> columnsFound = new List<string>();

            foreach (System.Data.DataColumn dc in AppData.ds.Tables[tableName].Columns)
            {
                string toFind = System.String.Concat("<", dc.ColumnName, ">");
                if (view.Contains(toFind)) columnsFound.Add(dc.ColumnName);
            }

            foreach (System.Data.DataRow dr in dt.Rows)
            {
                string temp = view;
                foreach (string s in columnsFound)
                {
                    temp = temp.Replace(System.String.Concat("<", s, ">"), dr[System.String.Concat(this.tableName + "_" + s)].ToString());
                }
                temp = temp.Replace(System.String.Concat("<", "id", ">"), dr[System.String.Concat(this.tableName + "_" + "id")].ToString());
                lo.Add(new AnnotatedGuid((Guid)dr[System.String.Concat(this.tableName, "_", "id")], temp));
            }

            return lo;
        }
        public override System.Windows.Forms.DataGridViewCell GridCellTemplate
        {
            get
            {
                System.Windows.Forms.DataGridViewComboBoxCell dgvcc = new System.Windows.Forms.DataGridViewComboBoxCell();
                dgvcc.ValueMember = "Object";
                dgvcc.DisplayMember = "View";
                return dgvcc;
            }
        }
        public override XmlElement ToXml(XmlDocument xdoc)
        {
            XmlElement xe = xdoc.CreateElement("Domain");
            xe.SetAttribute("Type", "Lookup");
            if (view != null) xe.SetAttribute("View", view);
            if (tableName != null) xe.SetAttribute("TableName", tableName);
            return xe;
        }
        public override XElement ToXElement()
        {
            var xe = new XElement("Domain", new XAttribute("Type", "Lookup"));
            if (view != null) xe.SetAttributeValue("View", view);
            if (tableName != null) xe.SetAttributeValue("TableName", tableName);
            return xe;
        }
        new internal static Lookup FromXElement(XElement xe)
        {
            return new Lookup(xe.Attribute("TableName").Value, xe.Attribute("View").Value);
        }
        public override Domain Clone
        {
            get { return new Lookup(this.tableName, this.view); }
        }
    }

    [TypeConverter(typeof(GuavaDomainConverter))]
    [Serializable]
    public class Decimal : Domain
    {
        decimal? min;
        decimal? max;
        public decimal? Min
        {
            get { return min; }
            set { min = value; }
        }
        public decimal? Max
        {
            get { return max; }
            set { max = value; }
        }
        public Decimal()
        {
            this.min = null;
            this.max = null;
        }
        public Decimal(decimal? min, decimal? max)
        {
            this.min = min;
            this.max = max;
        }
        public override bool Validate(object o)
        {
            decimal? i = null;

            if (o == null) return true;
            if (o is decimal?) i = o as decimal?;

            // If still null at this point, then o isn't a valid byte-worthy object
            if (i == null) return false;
            if ((min != null) && (min > i)) return false;
            if ((max != null) && (max < i)) return false;
            return true;
        }
        public override object ConvertString(string s)
        {
            if ((s == null) || (s == "")) return null;
            decimal d;
            if (System.Decimal.TryParse(s, out d))
            {
                if ((min != null) && (min > d)) throw new DomainConversionException("Value " + s + " is too small for a domain with minimum value " + min.ToString() + ".");
                if ((max != null) && (max < d)) throw new DomainConversionException("Value " + s + " is too big for a domain with maximum value " + max.ToString() + ".");
                return d;
            }
            else
            {
                throw new DomainConversionException("Could not convert " + s + " into a decimal number.");
            }
        }
        public override Type NaiveType
        {
            get { return typeof(decimal); }
        }
        public override string DBType
        {
            get { return "decimal"; }
        }
        public override bool Equals(object obj)
        {
            if (!(obj is Decimal)) return false;
            Decimal that = obj as Decimal;
            return ((this.max == that.max) && (this.min == that.min));
        }
        public override int GetHashCode()
        {
            return typeof(Decimal).GetHashCode() * (min.GetHashCode() + 1) + max.GetHashCode();
        }
        public override string ToString()
        {
            return "Numeric";
        }
        public override Domain Merge(Domain d)
        {
            if (!(d is Decimal)) return null;
            Decimal that = d as Decimal;
            decimal? nmax = (this.max == that.max) ? this.max : null;
            decimal? nmin = (this.min == that.min) ? this.min : null;
            return new Decimal(nmin, nmax);
        }
        public override Domain Upcast()
        {
            return null;
        }
        public override object UpcastValue(object o)
        {
            return null;
        }
        public override bool IsOrdered
        {
            get { return true; }
        }
        public override bool CanContain
        {
            get { return false; }
        }
        public override System.Windows.Forms.DataGridViewCell GridCellTemplate
        {
            get
            {
                DataGridViewNumberBoxCell dv = new DataGridViewNumberBoxCell();
                dv.Dom = GNumericDomains.FixedPoint;
                return dv;
            }
        }
        public override XmlElement ToXml(XmlDocument xdoc)
        {
            XmlElement xe = xdoc.CreateElement("Domain");
            xe.SetAttribute("Type", "Decimal");
            if (max != null) xe.SetAttribute("MaxValue", max.ToString());
            if (min != null) xe.SetAttribute("MinValue", min.ToString());
            return xe;
        }
        public override XElement ToXElement()
        {
            var xe = new XElement("Domain", new XAttribute("Type", "Decimal"));
            if (max != null) xe.SetAttributeValue("MaxValue", max.ToString());
            if (min != null) xe.SetAttributeValue("MinValue", min.ToString());
            return xe;
        }
        new internal static Decimal FromXElement(XElement xe)
        {
            var o = new Decimal();
            if (xe.Attribute("MaxValue") != null)
                o.max = decimal.Parse(xe.Attribute("MaxValue").Value);
            if (xe.Attribute("MinValue") != null)
                o.min = decimal.Parse(xe.Attribute("MinValue").Value);
            return o;
        }
        new internal static Decimal FromDBInfoRow(DataRow dr)
        {
            var o = new Decimal();
            return o;
        }
        public override Domain Clone
        {
            get { return new Decimal(this.min, this.max); }
        }
    }

    [TypeConverter(typeof(GuavaDomainConverter))]
    [Serializable]
    public class Single : Domain
    {
        float? min;
        float? max;
        public float? Min
        {
            get { return min; }
            set { min = value; }
        }
        public float? Max
        {
            get { return max; }
            set { max = value; }
        }
        public Single()
        {
            min = null;
            max = null;
        }
        public Single(float? min, float? max)
        {
            this.min = min;
            this.max = max;
        }
        public override bool Validate(object o)
        {
            float? i = null;

            if (o == null) return true;
            if (o is float?) i = o as float?;

            // If still null at this point, then o isn't a valid single-worthy object
            if (i == null) return false;
            if ((min != null) && (min > i)) return false;
            if ((max != null) && (max < i)) return false;
            return true;
        }
        public override object ConvertString(string s)
        {
            if ((s == null) || (s == "")) return null;
            float d;
            if (System.Single.TryParse(s, out d))
            {
                if ((min != null) && (min > d)) throw new DomainConversionException("Value " + s + " is too small for a domain with minimum value " + min.ToString() + ".");
                if ((max != null) && (max < d)) throw new DomainConversionException("Value " + s + " is too big for a domain with maximum value " + max.ToString() + ".");
                return d;
            }
            else
            {
                throw new DomainConversionException("Could not convert " + s + " into a floating-point number.");
            }
        }
        public override Type NaiveType
        {
            get { return typeof(float); }
        }
        public override string DBType
        {
            get { return "real"; }
        }
        public override bool Equals(object obj)
        {
            if (!(obj is Single)) return false;
            Single that = obj as Single;
            return ((this.max == that.max) && (this.min == that.min));
        }
        public override int GetHashCode()
        {
            return typeof(float).GetHashCode() * (min.GetHashCode() + 1) + max.GetHashCode();
        }
        public override string ToString()
        {
            return "Single";
        }
        public override Domain Merge(Domain d)
        {
            if (!(d is Single)) return null;
            Single that = d as Single;
            float? nmax = (this.max == that.max) ? this.max : null;
            float? nmin = (this.min == that.min) ? this.min : null;
            return new Single(nmin, nmax);
        }
        public override Domain Upcast()
        {
            return new Double((double?)min, (double?)max);
        }
        public override object UpcastValue(object o)
        {
            if (o == null) return null;
            if (o is float?) return (double?)o;
            return null;
        }
        public override bool IsOrdered
        {
            get { return true; }
        }
        public override bool CanContain
        {
            get { return false; }
        }
        public override System.Windows.Forms.DataGridViewCell GridCellTemplate
        {
            get
            {
                DataGridViewNumberBoxCell dv = new DataGridViewNumberBoxCell();
                dv.Dom = GNumericDomains.FloatingPointSingle;
                return dv;
            }
        }
        public override XmlElement ToXml(XmlDocument xdoc)
        {
            XmlElement xe = xdoc.CreateElement("Domain");
            xe.SetAttribute("Type", "Single");
            if (max != null) xe.SetAttribute("MaxValue", max.ToString());
            if (min != null) xe.SetAttribute("MinValue", min.ToString());
            return xe;
        }
        public override XElement ToXElement()
        {
            var xe = new XElement("Domain", new XAttribute("Type", "Single"));
            if (max != null) xe.SetAttributeValue("MaxValue", max.ToString());
            if (min != null) xe.SetAttributeValue("MinValue", min.ToString());
            return xe;
        }
        new internal static Single FromXElement(XElement xe)
        {
            var o = new Single();
            if (xe.Attribute("MaxValue") != null)
                o.max = float.Parse(xe.Attribute("MaxValue").Value);
            if (xe.Attribute("MinValue") != null)
                o.min = float.Parse(xe.Attribute("MinValue").Value);
            return o;
        }
        new internal static Single FromDBInfoRow(DataRow dr)
        {
            var o = new Single();
            return o;
        }
        public override Domain Clone
        {
            get { return new Single(this.min, this.max); }
        }
    }

    [TypeConverter(typeof(GuavaDomainConverter))]
    [Serializable]
    public class Double : Domain
    {
        double? min;
        double? max;
        public double? Min
        {
            get { return min; }
            set { min = value; }
        }
        public double? Max
        {
            get { return max; }
            set { max = value; }
        }
        public Double()
        {
            min = null;
            max = null;
        }
        public Double(double? min, double? max)
        {
            this.min = min;
            this.max = max;
        }
        public override bool Validate(object o)
        {
            double? i = null;

            if (o == null) return true;
            if (o is double?) i = o as double?;

            // If still null at this point, then o isn't a valid double-worthy object
            if (i == null) return false;
            if ((min != null) && (min > i)) return false;
            if ((max != null) && (max < i)) return false;
            return true;
        }
        public override object ConvertString(string s)
        {
            if ((s == null) || (s == "")) return null;
            double d;
            if (System.Double.TryParse(s, out d))
            {
                if ((min != null) && (min > d)) throw new DomainConversionException("Value " + s + " is too small for a domain with minimum value " + min.ToString() + ".");
                if ((max != null) && (max < d)) throw new DomainConversionException("Value " + s + " is too big for a domain with maximum value " + max.ToString() + ".");
                return d;
            }
            else
            {
                throw new DomainConversionException("Could not convert " + s + " into a floating-point number.");
            }
        }
        public override Type NaiveType
        {
            get { return typeof(double); }
        }
        public override string DBType
        {
            get { return "float"; }
        }
        public override bool Equals(object obj)
        {
            if (!(obj is Double)) return false;
            Double that = obj as Double;
            return ((this.max == that.max) && (this.min == that.min));
        }
        public override int GetHashCode()
        {
            return typeof(double).GetHashCode() * (min.GetHashCode() + 1) + max.GetHashCode();
        }
        public override string ToString()
        {
            return "Double";
        }
        public override Domain Merge(Domain d)
        {
            if (!(d is Double)) return null;
            Double that = d as Double;
            double? nmax = (this.max == that.max) ? this.max : null;
            double? nmin = (this.min == that.min) ? this.min : null;
            return new Double(nmin, nmax);
        }
        public override Domain Upcast()
        {
            return null;
        }
        public override object UpcastValue(object o)
        {
            return null;
        }
        public override bool IsOrdered
        {
            get { return true; }
        }
        public override bool CanContain
        {
            get { return false; }
        }
        public override System.Windows.Forms.DataGridViewCell GridCellTemplate
        {
            get
            {
                DataGridViewNumberBoxCell dv = new DataGridViewNumberBoxCell();
                dv.Dom = GNumericDomains.FloatingPointDouble;
                return dv;
            }
        }
        public override XmlElement ToXml(XmlDocument xdoc)
        {
            XmlElement xe = xdoc.CreateElement("Domain");
            xe.SetAttribute("Type", "Double");
            if (max != null) xe.SetAttribute("MaxValue", max.ToString());
            if (min != null) xe.SetAttribute("MinValue", min.ToString());
            return xe;
        }
        public override XElement ToXElement()
        {
            var xe = new XElement("Domain", new XAttribute("Type", "Double"));
            if (max != null) xe.SetAttributeValue("MaxValue", max.ToString());
            if (min != null) xe.SetAttributeValue("MinValue", min.ToString());
            return xe;
        }
        new internal static Double FromXElement(XElement xe)
        {
            var o = new Double();
            if (xe.Attribute("MaxValue") != null)
                o.max = double.Parse(xe.Attribute("MaxValue").Value);
            if (xe.Attribute("MinValue") != null)
                o.min = double.Parse(xe.Attribute("MinValue").Value);
            return o;
        }
        new internal static Double FromDBInfoRow(DataRow dr)
        {
            var o = new Double();
            return o;
        }
        public override Domain Clone
        {
            get { return new Double(this.min, this.max); }
        }
    }

    [TypeConverter(typeof(GuavaDomainConverter))]
    [Serializable]
    public class String : Domain
    {
        private int width;

        [DefaultValue(-1)]
        public int Width
        {
            get { return width; }
            set { width = value; }
        }

        public String()
        {
            width = -1;
        }
        public String(int w)
        {
            this.width = w;
        }
        public override bool Validate(object o)
        {
            if (! (o is string)) return false;
            if ((width >= 0) && ((o as string).Length > width)) return false;
            return true;
        }
        public override object ConvertString(string s)
        {
            if ((width >= 0) && (s.Length > width)) throw new DomainConversionException("\"" + s + "\" is longer than width" + width.ToString() + ".");
            return s;
        }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override Type NaiveType
        {
            get { return typeof(string); }
        }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override string DBType
        {
            get
            {
                if ((width < 0) || (width > 8000)) return "text";
                return "varchar(" + width.ToString() + ")";
            }
        }
        public override bool Equals(object obj)
        {
            if (! (obj is String)) return false;
            if ((obj as String).width != this.width && (obj as String).width != -1 && this.width != -1) return false;
            return true;
        }
        public override int GetHashCode()
        {
            return (typeof(String).GetHashCode()) + width.GetHashCode();
        }
        public override string ToString()
        {
            return "String";
        }
        public override Domain Merge(Domain d)
        {
            if (!(d is String)) return null;
            String sd = d as String;

            // If either length is null, return a new string domain of long length
            if ((this.width < 0) || (sd.width < 0)) return new String();
            
            // Otherwise, return a string domain with the larger width
            if (this.width > sd.width) return new String((int)this.width);
            return new String((int)sd.width);
        }
        public override Domain Upcast()
        {
            return null;
        }
        public override object UpcastValue(object o)
        {
            return null;
        }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override bool IsOrdered
        {
            get { return true; }
        }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override bool CanContain
        {
            get { return true; }
        }
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public override System.Windows.Forms.DataGridViewCell GridCellTemplate
        {
            get
            {
                System.Windows.Forms.DataGridViewTextBoxCell tbc = new System.Windows.Forms.DataGridViewTextBoxCell();
                if (width >= 0) tbc.MaxInputLength = width;
                return tbc;
            }
        }
        public override XmlElement ToXml(XmlDocument xdoc)
        {
            XmlElement xe = xdoc.CreateElement("Domain");
            xe.SetAttribute("Type", "String");
            if (width >= 0) xe.SetAttribute("Width", width.ToString());
            return xe;
        }
        public override XElement ToXElement()
        {
            var xe = new XElement("Domain", new XAttribute("Type", "String"));
            if (width >= 0) xe.SetAttributeValue("Width", width.ToString());
            return xe;
        }
        new internal static String FromXElement(XElement xe)
        {
            if (xe.Attribute("Width") != null)
                return new String(int.Parse(xe.Attribute("Width").Value));
            else
                return new String();
        }
        new internal static String FromDBInfoRow(DataRow dr)
        {
            int length= -1;
            try
            {
                if (dr["CHARACTER_MAXIMUM_LENGTH"] != null)
                    length = int.Parse(dr["CHARACTER_MAXIMUM_LENGTH"].ToString());
            }
            catch
            {
                length = -1;
            }

            if (AppData.testForEnum && length <= 50 && length != -1)
            {
                DataTable dt = DBConnection.ExecuteQuery("select " + dr["Column_Name"] + ", count(*) as count from " + dr["Table_Name"] + " group by " + dr["Column_Name"]).Tables[0];
                if (dt.Rows.Count > 1)
                {
                    string message = "Testing string column, "+  dr["Column_Name"] + ", in "+ dr["Table_Name"] + " for possible enumeration.\n \nStatistics: \n";

                    string indCount = dr["Column_Name"] + "\tCount\n---------------------------------\n";
                    foreach (DataRow stats in dt.Rows)
                    {
                        indCount = indCount + ((stats[dr["Column_Name"].ToString()]==null) ? "NULL" : stats[dr["Column_Name"].ToString()])  + "\t" + stats["count"] + "\n";


                    }
                    
                    message = message +indCount;

                    DialogResult res = MessageBox.Show(message, "Enumeration Test", MessageBoxButtons.YesNoCancel);
                    
                }
            }
            if (length != -1)
                return new String(length);
            else
                return new String();
        }
        public override Domain Clone
        {
            get { return new String(this.width); }
        }
    }

    [TypeConverter(typeof(GuavaDomainConverter))]
    [Serializable]
    public class DateTime : Domain
    {
        public override bool Validate(object o)
        {
            if (!(o is DateTime)) return false;
            return true;
        }
        public override object ConvertString(string s)
        {
            if ((s == null) || (s == "")) return null;
            try
            {
                return Convert.ToDateTime(s);
            }
            catch (InvalidCastException e)
            {
                throw new DomainConversionException(e.Message);
            }
        }
        public override Type NaiveType
        {
            get { return typeof(System.DateTime); }
        }
        public override string DBType
        {
            get { return "datetime"; }
        }
        public override bool Equals(object obj)
        {
            return (obj is DateTime);
        }
        public override int GetHashCode()
        {
            return typeof(System.DateTime).GetHashCode();
        }
        public override string ToString()
        {
            return "DateTime";
        }
        public override Domain Merge(Domain d)
        {
            if (d is DateTime) return this;
            return null;
        }
        public override Domain Upcast()
        {
            return null;
        }
        public override object UpcastValue(object o)
        {
            return null;
        }
        public override bool IsOrdered
        {
            get { return true; }
        }
        public override bool CanContain
        {
            get { return false; }
        }
        public override System.Windows.Forms.DataGridViewCell GridCellTemplate
        {
            get
            {
                return new DataGridViewDateTimeCell();
            }
        }
        public override XmlElement ToXml(XmlDocument xdoc)
        {
            XmlElement xe = xdoc.CreateElement("Domain");
            xe.SetAttribute("Type", "DateTime");
            return xe;
        }
        public override XElement ToXElement()
        {
            return new XElement("Domain", new XAttribute("Type", "DateTime"));
        }
        new public static DateTime FromXElement(XElement xe)
        {
            return new DateTime();
        }
        new public static DateTime FromDBInfoRow(DataRow dr)
        {
            return new DateTime();
        }
        public override Domain Clone
        {
            get { return new DateTime(); }
        }
    }

    [Serializable]
    public class AnnotatedGuid : Object
    {
        Guid g;
        string s;
        System.Data.DataRowView drv;

        public AnnotatedGuid(Guid g, string s)
        {
            this.g = g;
            this.s = s;
        }

        public AnnotatedGuid(Guid g, string s, System.Data.DataRowView drv)
        {
            this.g = g;
            this.s = s;
            this.drv = drv;
        }

        public override string ToString()
        {
            return s;
        }

        public Guid Object
        {
            get
            {
                return g;
            }
        }

        public string View
        {
            get
            {
                return s;
            }
        }

        public System.Data.DataRowView RowData
        {
            get
            {
                return drv;
            }
        }
    }

    public class GuavaDomainConverter : TypeConverter
    {
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == typeof(InstanceDescriptor))
                return true;
            return base.CanConvertTo(context, destinationType);
        }

        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (destinationType == typeof(InstanceDescriptor))
            {
                if (value is GuavaData.Domain.String)
                {
                    GuavaData.Domain.String o = value as GuavaData.Domain.String;
                    if (o.Width == -1)
                    {
                        System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.String).GetConstructor(new Type[] { });
                        return new InstanceDescriptor(ci, new object[] { });
                    }
                    else
                    {
                        System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.String).GetConstructor(new Type[] { typeof(int) });
                        return new InstanceDescriptor(ci, new object[] { o.Width });
                    }
                }
                if (value is GuavaData.Domain.Boolean)
                {
                    System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.Boolean).GetConstructor(new Type[] { });
                    return new InstanceDescriptor(ci, new object[] { });
                }
                if (value is GuavaData.Domain.DateTime)
                {
                    System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.DateTime).GetConstructor(new Type[] { });
                    return new InstanceDescriptor(ci, new object[] { });
                }
                if (value is GuavaData.Domain.UniqueIdentifier)
                {
                    System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.UniqueIdentifier).GetConstructor(new Type[] { });
                    return new InstanceDescriptor(ci, new object[] { });
                }
                if (value is GuavaData.Domain.Lookup)
                {
                    GuavaData.Domain.Lookup o = value as GuavaData.Domain.Lookup;
                    string a = o.TableName;
                    string b = o.View;
                    System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.Lookup).GetConstructor(new Type[] { typeof(string), typeof(string) });
                    return new InstanceDescriptor(ci, new object[] { a, b });
                }
                if (value is GuavaData.Domain.TinyInteger)
                {
                    GuavaData.Domain.TinyInteger o = value as GuavaData.Domain.TinyInteger;
                    byte? a = o.Min;
                    byte? b = o.Max;
                    if ((a == null) && (b == null))
                    {
                        System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.TinyInteger).GetConstructor(new Type[] { });
                        return new InstanceDescriptor(ci, new object[] { });
                    }
                    else
                    {
                        System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.TinyInteger).GetConstructor(new Type[] { typeof(byte?), typeof(byte?) });
                        return new InstanceDescriptor(ci, new object[] { a, b });
                    }
                }
                if (value is GuavaData.Domain.SmallInteger)
                {
                    GuavaData.Domain.SmallInteger o = value as GuavaData.Domain.SmallInteger;
                    short? a = o.Min;
                    short? b = o.Max;
                    if ((a == null) && (b == null))
                    {
                        System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.SmallInteger).GetConstructor(new Type[] { });
                        return new InstanceDescriptor(ci, new object[] { });
                    }
                    else
                    {
                        System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.SmallInteger).GetConstructor(new Type[] { typeof(short?), typeof(short?) });
                        return new InstanceDescriptor(ci, new object[] { a, b });
                    }
                }
                if (value is GuavaData.Domain.Integer)
                {
                    GuavaData.Domain.Integer o = value as GuavaData.Domain.Integer;
                    int? a = o.Min;
                    int? b = o.Max;
                    if ((a == null) && (b == null))
                    {
                        System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.Integer).GetConstructor(new Type[] { });
                        return new InstanceDescriptor(ci, new object[] { });
                    }
                    else
                    {
                        System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.Integer).GetConstructor(new Type[] { typeof(int?), typeof(int?) });
                        return new InstanceDescriptor(ci, new object[] { a, b });
                    }
                }
                if (value is GuavaData.Domain.BigInteger)
                {
                    GuavaData.Domain.BigInteger o = value as GuavaData.Domain.BigInteger;
                    long? a = o.Min;
                    long? b = o.Max;
                    if ((a == null) && (b == null))
                    {
                        System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.BigInteger).GetConstructor(new Type[] { });
                        return new InstanceDescriptor(ci, new object[] { });
                    }
                    else
                    {
                        System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.BigInteger).GetConstructor(new Type[] { typeof(long?), typeof(long?) });
                        return new InstanceDescriptor(ci, new object[] { a, b });
                    }
                }
                if (value is GuavaData.Domain.Single)
                {
                    GuavaData.Domain.Single o = value as GuavaData.Domain.Single;
                    float? a = o.Min;
                    float? b = o.Max;
                    if ((a == null) && (b == null))
                    {
                        System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.Single).GetConstructor(new Type[] { });
                        return new InstanceDescriptor(ci, new object[] { });
                    }
                    else
                    {
                        System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.Single).GetConstructor(new Type[] { typeof(float?), typeof(float?) });
                        return new InstanceDescriptor(ci, new object[] { a, b });
                    }
                }
                if (value is GuavaData.Domain.Double)
                {
                    GuavaData.Domain.Double o = value as GuavaData.Domain.Double;
                    double? a = o.Min;
                    double? b = o.Max;
                    if ((a == null) && (b == null))
                    {
                        System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.Double).GetConstructor(new Type[] { });
                        return new InstanceDescriptor(ci, new object[] { });
                    }
                    else
                    {
                        System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.Double).GetConstructor(new Type[] { typeof(double?), typeof(double?) });
                        return new InstanceDescriptor(ci, new object[] { a, b });
                    }
                }
                if (value is GuavaData.Domain.Decimal)
                {
                    GuavaData.Domain.Decimal o = value as GuavaData.Domain.Decimal;
                    decimal? a = o.Min;
                    decimal? b = o.Max;
                    if ((a == null) && (b == null))
                    {
                        System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.Decimal).GetConstructor(new Type[] { });
                        return new InstanceDescriptor(ci, new object[] { });
                    }
                    else
                    {
                        System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.Decimal).GetConstructor(new Type[] { typeof(decimal?), typeof(decimal?) });
                        return new InstanceDescriptor(ci, new object[] { a, b });
                    }
                }
                if (value is GuavaData.Domain.Enumerated)
                {
                    GuavaData.Domain.Enumerated o = value as GuavaData.Domain.Enumerated;
                    List<string> ls = o.Items;
                    System.Reflection.ConstructorInfo ci = typeof(GuavaData.Domain.Enumerated).GetConstructor(new Type[] { typeof(string[]) });
                    return new InstanceDescriptor(ci, new object[] { ls.ToArray() });
                }
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }
    }

}
